<?php

/**
 * Zend_Db_Table acl model adapter
 *
 * @author     Mon Zafra <monzee at gmail>
 * @copyright  (c)2009 Mon Zafra
 * @category   Mz
 * @package    modules
 * @subpackage admin
 * @license    http://mz-project.googlecode.com/svn/trunk/LICENSE    MIT License
 * @version    SVN: $Id: Zdt.php 47 2009-05-28 17:56:56Z monzee $
 */
class Admin_Model_Acl_Zdt implements Admin_Model_Acl_Adapter
{
    protected $_userTable;
    protected $_roleTable;
    protected $_permissionTable;

    /**
     * constructor
     *
     * possible option keys (case-sensitive):
     * - userTable       Zend_Db_Table_Abstract
     * - roleTable       ditto
     * - permissionTable ditto
     *
     * @param array|Zend_Config $options
     * @todo allow passing of strings to table options
     */
    public function __construct($options = array())
    {
        if (!empty($options)) {
            $this->setOptions($options);
        }
    }

    /**
     * Set adapter options.
     *
     * @param array|Zend_Config $options
     * @return Admin_Model_Acl_Array
     */
    public function setOptions($options)
    {
        if ($options instanceof Zend_Config) {
            $options = $options->toArray();
        } else if (!is_array($options)) {
            throw new Admin_Model_Acl_Exception('Invalid options passed to acl model adapter');
        }
        foreach ($options as $opt => $val) {
            $setter = 'set' . $opt;
            $this->$setter($val);
        }
        return $this;
    }

    /**
     * Catch set* calls.
     *
     * @param string $method
     * @param array  $args
     * @throws Admin_Model_Acl_Exception If an invalid set* method was called
     * @throws BadMethodCallException    If something other than set* was called
     */
    public function __call($method, $args)
    {
        if ('set' == substr($method, 0, 3)) {
            $prop = substr($method, 4);
            if (!in_array(strtolower($prop), array('usertable', 'roletable', 'permissionstable'))) {
                throw new Admin_Model_Acl_Exception("Invalid setter call. Must be one of: [ setUserTable, setRoleTable, setPermissionTable ] ");
            }
            $this->setTable($prop, $args[0]);
        } else {
            throw new BadMethodCallException('No such method (' . $method .').');
        }
    }

    /**
     * Set db table. CASE-SENSITIVE!
     * 
     * @param string                 $which
     * @param Zend_Db_Table_Abstract $table
     * @return Admin_Model_Acl_Zdt
     */
    public function setTable($which, Zend_Db_Table_Abstract $table)
    {
        $prop = '_' . strtolower($which[0]) . substr($which, 1);
        $this->$prop = $table;
        return $this;
    }

    /**
     * lazy load user table
     *
     * @return Zend_Db_Table_Abstract
     */
    public function getUserTable()
    {
        if (null === $this->_userTable) {
            $this->_userTable = new Admin_Model_DbTable_User(
                array('db' => Admin_Bootstrap::getDbAdapter())
            );
        } else if (is_string($this->_userTable)) {
            $this->_userTable = new $this->_userTable(
                array('db' => Admin_Bootstrap::getDbAdapter())
            );
        }
        return $this->_userTable;
    }

    /**
     * lazy load role table
     *
     * @return Zend_Db_Table_Abstract
     */
    public function getRoleTable()
    {
        if (null === $this->_roleTable) {
            $this->_roleTable = new Admin_Model_DbTable_Role(
                array('db' => Admin_Bootstrap::getDbAdapter())
            );
        } else if (is_string($this->_roleTable)) {
            $this->_roleTable = new $this->_roleTable(
                array('db' => Admin_Bootstrap::getDbAdapter())
            );
        }
        return $this->_roleTable;
    }

    /**
     * lazy load perm table
     *
     * @return Zend_Db_Table_Abstract
     */
    public function getPermissionTable()
    {
        if (null === $this->_permissionTable) {
            $this->_permissionTable = new Admin_Model_DbTable_Permission(
                array('db' => Admin_Bootstrap::getDbAdapter())
            );
        } else if (is_string($this->_permissionTable)) {
            $this->_permissionTable = new $this->_permissionTable(
                array('db' => Admin_Bootstrap::getDbAdapter())
            );
        }
        return $this->_permissionTable;
    }

    /**
     * Find a row by roleId.
     *
     * @param mixed $roleId
     * @return Zend_Db_Table_Row
     */
    public function getRoleById($roleId)
    {
        $roles = $this->getRoleTable();
        $sel = $roles->select()->where('id = ?', $roleId);
        return $roles->fetchRow($sel);
    }

    /**
     * Get parent roles of a role.
     *
     * @param mixed $role Role row
     * @return Zend_Db_Table_Rowset Rows containing only the 'id' column
     */
    public function getParentRoles($role)
    {
        $roleId = $role['id'];
        $roles = $this->getRoleTable();
        return $roles->getParentRoles($roleId);
    }

    /**
     * Get access rules for a resource.
     *
     * @param mixed $resId
     * @return Zend_Db_Table_Rowset
     */
    public function getRulesByResourceId($resId)
    {
        $perm = $this->getPermissionTable();
        return $perm->getRulesFor($resId);
    }

    /**
     * Find a row by username.
     *
     * @param string $username
     * @return Zend_Db_Table_Row
     */
    public function getUserByUsername($username)
    {
        $users = $this->getUserTable();
        $sel = $users->select()->where('username = ?', $username);
        return $users->fetchRow($sel);
    }

    /**
     * Get the immediate roles of a user.
     *
     * @param Zend_Db_Table_Row|array $user As long as it has an 'id' key
     * @return Zend_Db_Table_Rowset Rows containing only the 'id' column
     */
    public function getUserRoles($user)
    {
        $users = $this->getUserTable();
        return $users->getRoles($user);
    }

    /*
     * the next 3 functions are not part of the interface and are just used
     * for testing
     */

    public function getAllUsers()
    {
        $users = $this->getUserTable();
        return $users->fetchAll();
    }

    public function getAllRoles()
    {
        $roles = $this->getRoleTable();
        return $roles->fetchAll();
    }

    public function getAllPermissions()
    {
        $perm = $this->getPermissionTable();
        return $perm->fetchAll();
    }

}